home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 32
/
Aminet 32 (1999)(Schatztruhe)[!][Aug 1999].iso
/
Aminet
/
comm
/
tcp
/
Socks5.lha
/
Socks5
/
src
/
lib
/
msg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-10
|
9KB
|
292 lines
/* Copyright (c) 1995-1999 NEC USA, Inc. All rights reserved. */
/* */
/* The redistribution, use and modification in source or binary forms of */
/* this software is subject to the conditions set forth in the copyright */
/* document ("Copyright") included with this distribution. */
/*
* $Id: msg.c,v 1.30.2.1.2.4 1999/02/03 22:35:15 steve Exp $
*/
/* This file contains functions support reliable message transport under any */
/* (UDP or TCP) protocol. */
#include "socks5p.h"
#include "buffer.h"
#include "block.h"
#include "msg.h"
#include "log.h"
int S5IORecv(S5IOHandle fd, S5IOInfo *info, char *buf, int size, int ioflags, int libflags, double *timerm) {
int nr, sval, rlen = size;
struct timeval sv, *svpt;
fd_set fds, b;
#ifdef STRICT_TIMEOUT
struct timeval ts, te;
#endif
if (libflags & S5_IOFLAGS_TIMED && !timerm) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: NULL timeout pointer passed");
SETSOCKETERROR(ETIMEDOUT);
return -1;
}
if ((libflags & S5_IOFLAGS_NBYTES) && !(libflags & S5_IOFLAGS_RESTART)) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: Warning: Cannot reliably read n bytes and not handle restarts");
}
/* We may have read in some stuff and buffered it. Rather than replace */
/* select, lets just read the stuff *out* of the buffer first... */
while (1) {
if ((sval = S5BufCheckData(fd, info)) < 0) return -1;
if (sval == 0) break;
if ((nr = S5BufReadPacket(fd, info, buf, rlen, ioflags)) < 0) return -1;
if (nr == 0) return (size - rlen);
rlen -= nr; buf += nr;
if (!(libflags & S5_IOFLAGS_NBYTES)) return nr;
if (rlen == 0) return size;
}
/* Read again and again until we have an error, we run out of time, or */
/* we just read all that we wanted to. If STRICT_TIMEOUT is defined, */
/* subtract the amount of time we've spent at each point form the time */
/* we are allowing *total*...This is kind of expensive...An alternative, */
/* which has nearly the same consequences is is to spend that amount of */
/* time *each* read. If the data is too interspersed, it will die... */
FD_ZERO(&b);
FD_SET(fd, &b);
for (fds = b; rlen > 0; fds = b) {
if (libflags & S5_IOFLAGS_TIMED) {
sv.tv_sec = (int)*timerm;
sv.tv_usec = (int)((*timerm - (double)sv.tv_sec) * 1000000.0);
#ifdef STRICT_TIMEOUT
if (gettimeofday(&ts, NULL) < 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: gettimeofday failed: %m");
SETSOCKETERROR(ETIMEDOUT);
goto interrupted;
}
#endif
} else {
sv.tv_sec = 0;
sv.tv_usec = 0;
}
if (libflags & S5_IOFLAGS_TIMED) svpt = &sv;
else if (ISNBLOCK(fd) && !(libflags & S5_IOFLAGS_NBYTES)) svpt = &sv;
else svpt = NULL;
if ((sval = REAL(select)(fd + 1, &fds, NULL, NULL, svpt)) == 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "S5IORecv: select failed: Timed out");
if (libflags & S5_IOFLAGS_TIMED) SETSOCKETERROR(ETIMEDOUT);
#if defined(sun) && !defined(__svr4__)
else SETSOCKETERROR(EWOULDBLOCK);
#else
else SETSOCKETERROR(EAGAIN);
#endif
sval = -1;
goto interrupted;
}
#ifdef STRICT_TIMEOUT
if (libflags & S5_IOFLAGS_TIMED) {
if (gettimeofday(&te, NULL) < 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: gettimeofday failed: %m");
SETSOCKETERROR(ETIMEDOUT);
sval = -1;
goto interrupted;
}
*timerm -= (te.tv_sec - ts.tv_sec);
*timerm -= (te.tv_usec - ts.tv_usec)/1000000.0;
if (*timerm < 0.0) *timerm = 0.0;
}
#endif
if (sval < 0) {
if (ISSOCKETERROR(EINTR) && libflags & S5_IOFLAGS_RESTART) continue;
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: Select failed: %m");
goto interrupted;
}
while (rlen > 0) {
switch ((sval = S5BufCheckPacket(fd, info))) {
case 0:
case -1: goto interrupted;
default: break;
}
/* packet is not available... */
if (sval < 0) break;
if ((nr = S5BufReadPacket(fd, info, buf, rlen, ioflags)) <= 0) {
sval = nr;
goto interrupted;
}
if (!(libflags & S5_IOFLAGS_NBYTES)) return nr;
rlen -= nr;
buf += nr;
}
if (sval < 0 && !(libflags & S5_IOFLAGS_NBYTES)) {
sval = -1;
goto interrupted;
}
}
return size;
interrupted:
/* We read some data in, but we were interrupted and we aren't supposed */
/* to restart... So we have to store what we've read so far in info... */
if (S5BufUnreadPacket(info, buf-(size-rlen), size-rlen)) {
/* Nowhere to store what we've read... Bummer... */
}
return sval;
}
int S5IOSend(S5IOHandle fd, S5IOInfo *info, char *buf, int size, int flags, int libflags, double *timerm) {
struct timeval sv, *svpt;
int nw, wlen, sval;
fd_set fds, b;
#ifdef STRICT_TIMEOUT
struct timeval ts, te;
#endif
if (libflags & S5_IOFLAGS_TIMED && !timerm) {
SETSOCKETERROR(ETIMEDOUT);
return -1;
}
if ((libflags & S5_IOFLAGS_NBYTES) && !(libflags & S5_IOFLAGS_RESTART)) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: Warning: Cannot reliably write n bytes and not handle restarts");
}
FD_ZERO(&b);
FD_SET(fd, &b);
for (fds = b, wlen = size; wlen > 0; fds = b) {
if (libflags & S5_IOFLAGS_TIMED) {
sv.tv_sec = (int)*timerm;
sv.tv_usec = (int)((*timerm - (double)sv.tv_sec) * 1000000.0);
#ifdef STRICT_TIMEOUT
if (gettimeofday(&ts, NULL) < 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: gettimeofday failed: %m");
SETSOCKETERROR(ETIMEDOUT);
return -1;
}
#endif
} else {
sv.tv_sec = 0;
sv.tv_usec = 0;
}
if (libflags & S5_IOFLAGS_TIMED) svpt = &sv;
else if (ISNBLOCK(fd) && !(libflags & S5_IOFLAGS_NBYTES)) svpt = &sv;
else svpt = NULL;
if ((sval = REAL(select)(fd + 1, NULL, &fds, NULL, svpt)) == 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "S5IOSend: select failed: Timed out");
if (libflags & S5_IOFLAGS_TIMED) SETSOCKETERROR(ETIMEDOUT);
#if defined(sun) && !defined(__svr4__)
else SETSOCKETERROR(EWOULDBLOCK);
#else
else SETSOCKETERROR(EAGAIN);
#endif
return -1;
}
#ifdef STRICT_TIMEOUT
if (libflags & S5_IOFLAGS_TIMED) {
if (gettimeofday(&te, NULL) < 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: gettimeofday failed: %m");
SETSOCKETERROR(ETIMEDOUT);
return -1;
}
*timerm -= (te.tv_sec - ts.tv_sec);
*timerm -= (te.tv_usec - ts.tv_usec)/1000000.0;
if (*timerm < 0.0) *timerm = 0.0;
}
#endif
if (sval < 0) {
if (ISSOCKETERROR(EINTR) && libflags & S5_IOFLAGS_RESTART) continue;
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: Select failed: %m");
return -1;
}
do {
if ((nw = S5BufWritePacket(fd, info, buf, wlen, flags)) > 0) break;
if (ISSOCKETERROR(EINTR) && !(libflags & S5_IOFLAGS_RESTART)) break;
if ((ISSOCKETERROR(EWOULDBLOCK) || ISSOCKETERROR(EAGAIN)) && !(libflags & S5_IOFLAGS_NBYTES)) break;
nw = 0;
} while (S5IOCheck(fd) >= 0);
if (nw < 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: failed: %m");
return nw;
}
if (nw == 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: peer closed");
SETSOCKETERROR(EPIPE);
return -1;
}
if (!(libflags & S5_IOFLAGS_NBYTES)) return nw;
wlen -= nw;
buf += nw;
}
return size;
}
/* See what's going on with a socket -- is the connection still valid? */
int S5IOCheck(S5IOHandle fd) {
struct timeval tv = { 0, 0 };
fd_set rfds, b;
char dummy;
int sv, n;
FD_ZERO(&b);
FD_SET(fd, &b);
S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5IOCheck: Checking socket status");
/* Poll the file descriptor real quick, and see what comes back... */
while (1) {
rfds = b;
switch ((sv = REAL(select)(fd+1, &rfds, NULL, NULL, &tv))) {
case 1:
/* Something happened -- either an error or data, ok to recv */
n = RECVSOCKET(fd, &dummy, 1, MSG_PEEK);
if (n < 0 && ISSOCKETERROR(EINTR)) continue;
else if (n <= 0) {
S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(1), 0, "S5IOCheck: recv failed: %m");
return -1;
}
/* fallthrough -- there is real data there... */
case 0:
/* Nothing's happening -- no error, all's ok. */
S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5IOCheck: ok");
return sv;
default:
/* Not a valid socket (?). */
if (ISSOCKETERROR(EINTR)) continue;
S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOCheck: select failed: %m");
return -1;
}
}
}